<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        function loadImage(src,resove,reject) {
            console.log(1)
            let img = new Image()
            img.src = src
            img.onload = ()=>{
                resove(img)
            }
            img.onerror = reject
        }
        loadImage('https://picsum.photos/200/300',img=>{
            console.log('image loaded')
            document.body.appendChild(img)
        },()=>{
            console.log('图片加载失败')
        })
        
        console.log('我先执行')
        // 对于图片加载，是异步的
        /*
            详细解释：
                事件循环简介
               JavaScript 是单线程的，这意味着它一次只能执行一个任务。然而，为了支持非阻塞操作（如网络请求、定时器等），JavaScript 使用了一个叫做“事件循环”的机制来管理这些异步任务。

               事件循环不断地运行，检查调用栈是否为空，并决定是否将回调函数从任务队列移到调用栈中执行。调用栈用于跟踪当前正在执行的函数调用，而任务队列则存放了等待执行的回调函数。

               与上述代码的联系
               在你提供的 loadImage 函数例子中，当调用 loadImage('https://picsum.photos/200/300') 开始加载图片时，这个过程是异步的。JavaScript 不会因为等待图片加载完成而停止执行后续代码，也就是说，console.log('我先执行') 会被立即执行，无需等待图片加载完成。
               
               同步代码执行：首先，所有同步代码按照它们出现的顺序执行。在这个例子中，包括创建 Image 对象和设置它的 src 属性，以及紧接着的 console.log('我先执行') 输出。
               异步操作：图片加载是一个典型的异步操作。一旦开始加载图片，浏览器会在后台处理这个请求。无论图片加载成功还是失败，相应的回调函数（onload 或 onerror）都会被放到任务队列中等待执行。
               事件循环的作用：当调用栈为空（即所有的同步代码执行完毕），事件循环会检查任务队列，并将处于队列前端的回调函数移入调用栈中执行。在这个例子中，一旦图片加载完成（或加载失败），对应的 img.onload 或 img.onerror 回调函数就会被执行，输出 "image loaded" 或 "image error" 到控制台。
               因此，事件循环确保了即使有耗时的异步操作（如网络请求），JavaScript 代码仍然能够保持响应，通过有效地管理同步代码和异步回调的执行顺序实现这一点。这正是你在示例中看到的为什么 "我先执行" 会先于图片加载的结果被打印出来的原因。
        
        */
    </script>

    <script>
        function interval(callback,delay=100){
            let id = setInterval(()=>callback(id),delay)
        }
        interval((timeId)=>{
            console.log(    timeId)
            console.log('hello')
        },1000)
    </script>
</body>

</html>